package Engine.World;

import java.util.Random;

import org.lwjgl.opengl.GL11;

import Engine.Blocks.Air;
import Engine.Blocks.Bedrock;
import Engine.Blocks.DefaultBlock;
import Engine.Blocks.Dirt;
import Engine.Blocks.DrawInfos;
import Engine.Blocks.Gras;
import Engine.Blocks.Nothing;
import Engine.Blocks.Stone;
import Engine.Blocks.Water;

/**
 * @author vbdetlevvb
 * 
 */
public class Chunk {

	byte TerrainHeight = 127;
	byte TerrainWidth = 16;
	int seed;
	DefaultBlock blocks[][];
	boolean IsGenerated = false;

	public Chunk() {
		blocks = new DefaultBlock[TerrainHeight][TerrainWidth];
	}

	public void Generate(int seed, int cx, Random random) {
		this.seed = seed;
		for (int y = 0; y < TerrainHeight; y++) {
			// XReihe Durchgehen
			for (int x = 0; x < TerrainWidth; x++) {
				blocks[y][x] = new Air();
				if (y == TerrainHeight)
					blocks[y][x] = new Bedrock();
			}
		}
		// for (int y = 0; y < TerrainHeight; y++) {
		// XReihe Durchgehen
		for (int x = 0; x < TerrainWidth; x++) {
			// Sys.alert("Pos", "X:"+x+" Y: "+y +
			// " BLocks: "+blocks.length);
			/*
			 * if (y > TerrainHeight - 10+(5*Math.sin(x/seed))) { blocks[y][x] =
			 * new Dirt(); } if (y == (int)(TerrainHeight
			 * -10+(5*Math.sin(x/seed)))) {
			 * 
			 * }
			 */
			for (int y = TerrainHeight - 2; y > GetTerrainHeight(x + (cx * 16)); y--) {
				blocks[y][x] = new Dirt();
			}
			for (int y = TerrainHeight - 2; y > GetTerrainHeight(x + (cx * 16))
					+ 4 + random.nextInt(2); y--) {
				if (y >= 0)
					blocks[y][x] = new Stone();
			}
			for (int y = TerrainHeight - 2; y > TerrainHeight - 15; y--) {
				if (y >= 0)
					if (blocks[y][x].ID() == (new Air()).ID())
						blocks[y][x] = new Water();
			}
			blocks[GetTerrainHeight(x + (cx * 16))][x] = new Gras();

		}
		IsGenerated = true;
	}

	double r1, r2 = 0;

	public class Render extends Thread {
		DrawInfos di;
		int X;

		public Render(DrawInfos di, int X) {
			this.X = X;
			this.di = di;
		}

		public void run() {
			try {
				if (IsGenerated) {

					GL11.glPushMatrix();
					GL11.glTranslatef(X * 16 * 16, 0, 0);
					for (int y = TerrainHeight - 1; y >= 0; y--) {
						// XReihe Durchgehen
						for (int x = 0; x < TerrainWidth; x++) {

							blocks[y][x].Draw(di, x, y);
						}
					}
					GL11.glPopMatrix();

				} else {
					System.out.println(X);
				}
			} catch (Exception ex) {

			}
		}
	}

	private int GetTerrainHeight(int x) {
		int Chunk = (int) (x / 16);

		r1 = RandomYHeight((Chunk - 1) * seed) * 5;
		r2 = RandomYHeight((Chunk) * seed) * 5;

		while (x >= 16)
			x -= 16;
		// System.out.println("Chunk: "+Chunk+" R1: "+r1+" R2: "+r2+ " X: "+((x
		// / 1.0)));
		return TerrainHeight - 15
				- (int) (Cosine_Interpolate(r1, r2, (x / 16.0)));

	}

	private double RandomYHeight(int x) {

		return 1.0 - ((x * (x * x * 15731 + 789221) + 1376312589) * 0x7fffffff) / 1073741824.0;
	}

	public double Cosine_Interpolate(double a, double b, double x) {
		double ft = x * 3.1415927;
		double f = (1 - Math.cos(ft)) * .5;

		return a * (1 - f) + b * f;
	}

	public DefaultBlock getBlockAt(int X, int Y) {
		try {
			// System.out.println(blocks[Y][X].ID());
			return blocks[Y][X];

		} catch (Exception ex) {
			// System.out.println("No in Terrain Physic: X: " + X + " Y: " + Y);
			return new Air();
		}

	}

	public Thread Draw(int X, DrawInfos di) {
		Render render = new Render(di, X);
		render.run();
		return render;
	}

}
